package com.king.modules.system.service.impl;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.king.common.constant.UserConstants;
import com.king.common.exception.AssertHelper;
import com.king.common.utils.SecurityUtils;
import com.king.common.utils.spring.SpringUtils;
import com.king.common.utils.text.StringUtils;
import com.king.framework.base.domain.vo.LoginUser;
import com.king.framework.base.service.impl.YyBaseServiceImpl;
import com.king.framework.security.service.JwtTokenService;
import com.king.framework.security.service.SysPermissionService;
import com.king.modules.system.domain.SysRoleEntity;
import com.king.modules.system.domain.SysRoleMenuEntity;
import com.king.modules.system.domain.SysUserEntity;
import com.king.modules.system.domain.vo.RoleMenuResForm;
import com.king.modules.system.mapper.SysRoleMapper;
import com.king.modules.system.service.SysMenuService;
import com.king.modules.system.service.SysRoleMenuService;
import com.king.modules.system.service.SysRoleService;
import com.king.modules.system.service.SysUserRoleService;
import com.king.modules.system.service.SysUserService;

/**
 * 角色 业务层处理
 * 
 * @author king
 */
@Service
public class SysRoleServiceImpl extends YyBaseServiceImpl<SysRoleMapper, SysRoleEntity, Long> implements SysRoleService {
	@Autowired
	private SysRoleMapper roleMapper;

	@Autowired
	private SysRoleMenuService roleMenuService;

	@Autowired
	private SysUserRoleService userRoleService;

	@Autowired
	private SysUserService userService;

	@Autowired
	private SysMenuService menuService;
	
	@Autowired
	private JwtTokenService tokenService;

	@Autowired
	private SysPermissionService permissionService;
	
	

	@Override
	public void beforeAdd(SysRoleEntity entity) throws Exception {
		AssertHelper.getInstance().checkException(UserConstants.NOT_UNIQUE.equals(checkRoleNameUnique(entity)),
				"新增角色'" + entity.getRoleName() + "'失败，角色名称已存在");
		AssertHelper.getInstance().checkException(UserConstants.NOT_UNIQUE.equals(checkRoleKeyUnique(entity)),
				"新增角色'" + entity.getRoleName() + "'失败，角色权限已存在");
//		entity.setCr(getUserId());
		super.beforeAdd(entity);
	}
	

	@Override
	public SysRoleEntity doUpdate(SysRoleEntity entity) throws Exception {
		checkRoleAllowed(entity);
		checkRoleDataScope(entity.getId());
		AssertHelper.getInstance().checkException(UserConstants.NOT_UNIQUE.equals(checkRoleNameUnique(entity)),
				"新增角色'" + entity.getRoleName() + "'失败，角色名称已存在");
		AssertHelper.getInstance().checkException(UserConstants.NOT_UNIQUE.equals(checkRoleKeyUnique(entity)),
				"新增角色'" + entity.getRoleName() + "'失败，角色权限已存在");

		// 更新缓存用户权限
		LoginUser loginUser = SecurityUtils.getLoginUser();
		if (StringUtils.isNotNull(loginUser.getUser()) && !loginUser.getUser().isAdmin()) {
			loginUser.setPermissions(permissionService.getMenuPermission(loginUser.getUser()));
			loginUser.setUser(userService.selectUserByUserName(loginUser.getUser().getUserName()));
			tokenService.setLoginUser(loginUser);
		}
		return super.doUpdate(entity);
	}


	@Override
	public void beforeDelete(SysRoleEntity entity) throws Exception {
		checkRoleAllowed(new SysRoleEntity(entity.getId()));
		checkRoleDataScope(entity.getId());
		// 删除角色与菜单关联
		roleMenuService.deleteRoleMenuByRoleId(entity.getId());
		
		userRoleService.deleteByRoleId(entity.getId());
		
		super.beforeDelete(entity);
	}


	/**
	 * 根据条件分页查询角色数据
	 * 
	 * @param role
	 *            角色信息
	 * @return 角色数据集合信息
	 */
	@Override
	public List<SysRoleEntity> selectRoleList(SysRoleEntity role) {
		return roleMapper.selectRoleList(role);
	}

	/**
	 * 根据用户ID查询角色
	 * 
	 * @param userId
	 *            用户ID
	 * @return 角色列表
	 */
	@Override
	public List<SysRoleEntity> selectRolesByUserId(Long userId) {
		List<SysRoleEntity> userRoles = roleMapper.selectRolePermissionByUserId(userId);
		List<SysRoleEntity> roles = selectRoleAll();
		for (SysRoleEntity role : roles) {
			for (SysRoleEntity userRole : userRoles) {
				if (role.getId().longValue() == userRole.getId().longValue()) {
					role.setFlag(true);
					break;
				}
			}
		}
		return roles;
	}

	/**
	 * 根据用户ID查询权限
	 * 
	 * @param userId
	 *            用户ID
	 * @return 权限列表
	 */
	@Override
	public Set<String> selectRolePermissionByUserId(Long userId) {
		List<SysRoleEntity> perms = roleMapper.selectRolePermissionByUserId(userId);
		Set<String> permsSet = new HashSet<>();
		for (SysRoleEntity perm : perms) {
			if (StringUtils.isNotNull(perm)) {
				permsSet.addAll(Arrays.asList(perm.getRoleKey().trim().split(",")));
			}
		}
		return permsSet;
	}

	/**
	 * 查询所有角色
	 * 
	 * @return 角色列表
	 */
	@Override
	public List<SysRoleEntity> selectRoleAll() {
		return SpringUtils.getAopProxy(this).selectRoleList(new SysRoleEntity());
	}

	/**
	 * 根据用户ID获取角色选择框列表
	 * 
	 * @param userId
	 *            用户ID
	 * @return 选中角色ID列表
	 */
	@Override
	public List<Long> selectRoleListByUserId(Long userId) {
		return roleMapper.selectRoleListByUserId(userId);
	}

	/**
	 * 通过角色ID查询角色
	 * 
	 * @param roleId
	 *            角色ID
	 * @return 角色对象信息
	 */
	@Override
	public SysRoleEntity selectRoleById(Long roleId) {
		return roleMapper.selectRoleById(roleId);
	}

	/**
	 * 校验角色名称是否唯一
	 * 
	 * @param role
	 *            角色信息
	 * @return 结果
	 */
	@Override
	public String checkRoleNameUnique(SysRoleEntity role) {
		Long roleId = StringUtils.isNull(role.getId()) ? -1L : role.getId();
		SysRoleEntity info = roleMapper.checkRoleNameUnique(role.getRoleName());
		if (StringUtils.isNotNull(info) && info.getId().longValue() != roleId.longValue()) {
			return UserConstants.NOT_UNIQUE;
		}
		return UserConstants.UNIQUE;
	}

	/**
	 * 校验角色权限是否唯一
	 * 
	 * @param role
	 *            角色信息
	 * @return 结果
	 */
	@Override
	public String checkRoleKeyUnique(SysRoleEntity role) {
		Long roleId = StringUtils.isNull(role.getId()) ? -1L : role.getId();
		SysRoleEntity info = roleMapper.checkRoleKeyUnique(role.getRoleKey());
		if (StringUtils.isNotNull(info) && info.getId().longValue() != roleId.longValue()) {
			return UserConstants.NOT_UNIQUE;
		}
		return UserConstants.UNIQUE;
	}

	/**
	 * 校验角色是否允许操作
	 * 
	 * @param role
	 *            角色信息
	 */
	@Override
	public void checkRoleAllowed(SysRoleEntity role) {
		if (StringUtils.isNotNull(role.getId()) && role.isAdmin()) {
			AssertHelper.getInstance().throwException("不允许操作超级管理员角色");
		}
	}

	/**
	 * 校验角色是否有数据权限
	 * 
	 * @param roleId
	 *            角色id
	 */
	@Override
	public void checkRoleDataScope(Long roleId) {
		if (!SysUserEntity.isAdmin(SecurityUtils.getUserId())) {
			SysRoleEntity role = new SysRoleEntity();
			role.setId(roleId);
			List<SysRoleEntity> roles = SpringUtils.getAopProxy(this).selectRoleList(role);
			if (StringUtils.isEmpty(roles)) {
				AssertHelper.getInstance().throwException("没有权限访问角色数据！");
			}
		}
	}

	/**
	 * 通过角色ID查询角色使用数量
	 * 
	 * @param roleId
	 *            角色ID
	 * @return 结果
	 */
	@Override
	public int countUserRoleByRoleId(Long roleId) {
		return userRoleService.countUserRoleByRoleId(roleId);
	}



	/**
	 * 修改角色状态
	 * 
	 * @param role
	 *            角色信息
	 * @return 结果
	 */
	@Transactional
	@Override
	public int updateRoleStatus(SysRoleEntity role) {
		return roleMapper.updateRole(role);
	}



	/**
	 * 通过角色ID删除角色
	 * 
	 * @param roleId
	 *            角色ID
	 * @return 结果
	 */
	@Override
	@Transactional
	public int deleteRoleById(Long roleId) {
		checkRoleAllowed(new SysRoleEntity(roleId));
		checkRoleDataScope(roleId);
		// 删除角色与菜单关联
		roleMenuService.deleteRoleMenuByRoleId(roleId);
		
		userRoleService.deleteByRoleId(roleId);
		// 删除角色与部门关联
		return roleMapper.deleteRoleById(roleId);
	}

	/**
	 * 批量删除角色信息
	 * 
	 * @param roleIds
	 *            需要删除的角色ID
	 * @return 结果
	 */
	@Override
	@Transactional
	public int deleteRoleByIds(Long[] roleIds) {
		for (Long roleId : roleIds) {
			checkRoleAllowed(new SysRoleEntity(roleId));
			checkRoleDataScope(roleId);
			SysRoleEntity role = selectRoleById(roleId);
			if (countUserRoleByRoleId(roleId) > 0) {
				AssertHelper.getInstance().throwException(String.format("%1$s已分配,不能删除", role.getRoleName()));
			}
		}
		// 删除角色与菜单关联
		roleMenuService.deleteRoleMenuByRoleIds(roleIds);
		return roleMapper.deleteRoleByIds(roleIds);
	}


	/**
	 * 批量取消授权用户角色
	 * 
	 * @param roleId
	 *            角色ID
	 * @param userIds
	 *            需要取消授权的用户数据ID
	 * @return 结果
	 */
	@Transactional
	@Override
	public int deleteAuthUsers(Long roleId, Long[] userIds) {
		return userRoleService.deleteAuthUsers(roleId, userIds);
	}

	/**
	 * 批量选择授权用户角色
	 * 
	 * @param roleId
	 *            角色ID
	 * @param userIds
	 *            需要授权的用户数据ID
	 * @return 结果
	 */
	@Transactional
	@Override
	public int insertAuthUsers(Long roleId, Long[] userIds) {
		return userRoleService.insertAuthUsers(roleId, userIds);
	}

	/**
	 * 保存角色和菜单关联
	 */
	@Transactional
	@Override
	public int authMenuRes(RoleMenuResForm form) {
		List<Long> menuIds = menuService.selectMenuIdsByRoleId(form.getRoleId());
		Set<Long> menuIdSet = menuIds.stream().map(Function.identity()).collect(Collectors.toSet());
		Long []newMenuIds = form.getMenuIds();
		List<SysRoleMenuEntity> list = new ArrayList<SysRoleMenuEntity>();
		for(Long menuId : newMenuIds){
			if(menuIdSet.contains(menuId)){
				continue;
			}
			SysRoleMenuEntity rm = new SysRoleMenuEntity();
			setBaseEntity(rm);
			rm.setRoleId(form.getRoleId());
			rm.setMenuId(menuId);
			list.add(rm);
		}
		List<Long> delIds = new ArrayList<>();
		boolean exit = false;
		for(Long menuId : menuIds){
			exit = false;
			for(Long newId : newMenuIds){
				if(newId.longValue()== menuId.longValue()){
					exit = true;
					break;
				}
			}
			if(!exit){
				delIds.add(menuId);
			}
		}
		if(delIds.size()>0){
			roleMenuService.deleteRoleMenuByRoleIdAndMenuIds(form.getRoleId(), delIds.stream().toArray(Long[]::new));
		}
		if(CollectionUtils.isEmpty(list)){
			return 0;
		}
		boolean suc = roleMenuService.saveBatch(list);
		if(suc){
			return list.size();
		}
		return 0;
	}

}
